<template>
  <div class="app">
    <!-- 头部 -->
    <header class="app-header">
      <button class="back-btn" @click="goBack" aria-label="返回">
        <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M15 18l-6-6 6-6" />
        </svg>
      </button>
      <div class="brand">
        <div class="brand-icon" aria-hidden="true">
          <svg viewBox="0 0 24 24" class="icon" fill="none" stroke="currentColor" stroke-width="2"
            stroke-linecap="round" stroke-linejoin="round">
            <circle cx="12" cy="12" r="10" />
            <circle cx="12" cy="12" r="6" />
            <circle cx="12" cy="12" r="2" />
          </svg>
        </div>
        <div class="brand-text">
          <h1 class="title">减肥打卡</h1>
          <p class="subtitle">坚持就是胜利 💪</p>
        </div>
      </div>
      <div class="rank-box">
        <div class="rank">第{{ userRank }}名</div>
        <div class="rank-sub">{{ getCompletionRate(currentUser) }}% 完成</div>
      </div>
    </header>

    <main class="container">
      <!-- 本周概览 -->
      <section class="card">
        <div class="card-head">
          <h2 class="card-title">本周打卡记录</h2>
          <div class="card-meta">
            <svg viewBox="0 0 24 24" class="meta-icon" fill="none" stroke="currentColor" stroke-width="2"
              stroke-linecap="round" stroke-linejoin="round">
              <rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
              <line x1="16" y1="2" x2="16" y2="6" />
              <line x1="8" y1="2" x2="8" y2="6" />
              <line x1="3" y1="10" x2="21" y2="10" />
            </svg>
            本周
          </div>
        </div>

        <!-- 日期头部 -->
        <div class="week-head">
          <div class="cell muted"></div>
          <div v-for="day in weekDates" :key="day.fullDate" class="cell">
            <div class="dow">{{ day.day }}</div>
            <div class="dom" :class="{ today: day.isToday }">{{ day.date }}</div>
          </div>
        </div>

        <!-- 成员打卡记录 -->
        <div class="member-list">
          <div v-for="member in members" :key="member" class="member-row" :class="{ me: member === currentUser }">
            <div class="member-meta">
              <div class="name">
                {{ member }} <span v-if="member === currentUser" class="me-badge">👤</span>
              </div>
              <div class="rate">{{ getCompletionRate(member) }}%</div>
              <svg v-if="ranking[0]?.name === member" viewBox="0 0 24 24" class="trophy" fill="currentColor">
                <path
                  d="M4 4h16v3a4 4 0 0 1-4 4 4 4 0 0 1-8 0A4 4 0 0 1 4 7V4zm8 9a6 6 0 0 0 6-6h2a4 4 0 0 1-4 4h-1a6 6 0 0 1-3 4.9V18h3v2H8v-2h3v-2.1A6 6 0 0 1 8 11H7A4 4 0 0 1 3 7h2a6 6 0 0 0 7 6z" />
              </svg>
            </div>

            <div v-for="day in weekDates" :key="day.fullDate" class="check-cell">
              <button class="check-btn" :class="[
                checkinData[member][day.fullDate].checked ? 'checked' : 'unchecked',
                day.isToday ? 'today' : '',
                (member !== currentUser && checkinData[member][day.fullDate].checked && checkinData[member][day.fullDate].note) ? 'peekable' : ''
              ]"
                :title="(member !== currentUser && checkinData[member][day.fullDate].checked && checkinData[member][day.fullDate].note) ? '点击查看记录' : ''"
                :disabled="!(member === currentUser) && !(checkinData[member][day.fullDate].checked && checkinData[member][day.fullDate].note)"
                @click="onDayCellClick(member, day.fullDate)">
                <svg v-if="checkinData[member][day.fullDate].checked" viewBox="0 0 24 24" class="icon-s" fill="none"
                  stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
                  <polyline points="22 4 12 14.01 9 11.01" />
                </svg>
                <svg v-else viewBox="0 0 24 24" class="icon-s" fill="none" stroke="currentColor" stroke-width="2"
                  stroke-linecap="round" stroke-linejoin="round">
                  <circle cx="12" cy="12" r="10" />
                </svg>
                <span
                  v-if="checkinData[member][day.fullDate].checked && checkinData[member][day.fullDate].note && member !== currentUser"
                  class="dot" />
              </button>
            </div>
          </div>
        </div>
      </section>

      <!-- 排行榜 -->
      <section class="card">
        <div class="card-head">
          <div class="trend">
            <svg viewBox="0 0 24 24" class="meta-icon" fill="none" stroke="currentColor" stroke-width="2"
              stroke-linecap="round" stroke-linejoin="round">
              <polyline points="23 7 16 14 10 8 1 17" />
              <polyline points="17 7 23 7 23 13" />
            </svg>
            <h3 class="card-title">本周排行</h3>
          </div>
        </div>

        <div class="ranking">
          <div v-for="(rank, index) in ranking" :key="rank.name" class="rank-row"
            :class="{ mine: rank.name === currentUser }">
            <div class="rank-left">
              <div class="rank-no" :class="['no-' + (index + 1)]">{{ index + 1 }}</div>
              <div class="rank-name">
                {{ rank.name }}<span v-if="rank.name === currentUser" class="me-badge">👤</span>
              </div>
            </div>
            <div class="rank-right">
              <div class="rate-strong">{{ rank.rate }}%</div>
              <div class="rate-sub">{{ Math.round((rank.rate * 7) / 100) }}天完成</div>
              <svg v-if="index === 0" viewBox="0 0 24 24" class="trophy" fill="currentColor">
                <path
                  d="M4 4h16v3a4 4 0 0 1-4 4 4 4 0 0 1-8 0A4 4 0 0 1 4 7V4zm8 9a6 6 0 0 0 6-6h2a4 4 0 0 1-4 4h-1a6 6 0 0 1-3 4.9V18h3v2H8v-2h3v-2.1A6 6 0 0 1 8 11H7A4 4 0 0 1 3 7h2a6 6 0 0 0 7 6z" />
              </svg>
            </div>
          </div>
        </div>
      </section>

      <!-- 今日打卡 -->
      <section class="card">
        <h3 class="card-title mb">今日打卡</h3>
        <div v-for="today in weekDates.filter(d => d.isToday)" :key="today.fullDate" class="today-wrap">
          <template v-if="checkinData[currentUser][today.fullDate].checked">
            <button class="btn done" disabled>
              <svg viewBox="0 0 24 24" class="icon-m" fill="none" stroke="currentColor" stroke-width="2"
                stroke-linecap="round" stroke-linejoin="round">
                <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
                <polyline points="22 4 12 14.01 9 11.01" />
              </svg>
              今日已打卡 ✨
            </button>
            <div v-if="checkinData[currentUser][today.fullDate].note" class="note-panel">
              <div class="note-label">今日记录：</div>
              <div class="note-text">{{ checkinData[currentUser][today.fullDate].note }}</div>
            </div>
          </template>
          <template v-else>
            <div class="field">
              <textarea v-model="todayNote" class="textarea" maxlength="100"
                placeholder="记录一下今天的运动和饮食情况吧...&#10;例如：跑步30分钟，晚餐只吃了沙拉"></textarea>
              <div class="hint">
                <span class="muted">{{ todayNote.length }}/100</span>
                <span class="muted">记录让坚持更有意义 ✨</span>
              </div>
            </div>
            <button class="btn primary" :disabled="!todayNote.trim()" @click="handleTodayCheckin()">
              <svg viewBox="0 0 24 24" class="icon-m" fill="none" stroke="currentColor" stroke-width="2"
                stroke-linecap="round" stroke-linejoin="round">
                <circle cx="12" cy="12" r="10" />
                <circle cx="12" cy="12" r="6" />
                <circle cx="12" cy="12" r="2" />
              </svg>
              完成今日打卡
            </button>
          </template>
        </div>
      </section>

      <!-- 底部提示 -->
      <section class="tip">
        <div class="tip-icon" aria-hidden="true">
          <svg viewBox="0 0 24 24" class="icon" fill="none" stroke="currentColor" stroke-width="2"
            stroke-linecap="round" stroke-linejoin="round">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
            <circle cx="9" cy="7" r="4" />
            <path d="M23 21v-2a4 4 0 0 0-3-3.87" />
            <path d="M16 3.13a4 4 0 0 1 0 7.75" />
          </svg>
        </div>
        <div>
          <p class="tip-title">加油！坚持就是胜利</p>
          <p class="tip-desc">本周你已完成 {{ Math.round(getCompletionRate(currentUser) * 7 / 100) }} 天，继续保持！</p>
        </div>
      </section>
    </main>

    <!-- 查看好友记录弹窗 -->
    <div v-if="showNoteModal && selectedNote" class="modal">
      <div class="modal-panel">
        <div class="modal-head">
          <h3 class="modal-title">{{ selectedNote.member }} 的打卡记录</h3>
          <p class="modal-sub">{{ selectedNote.dayText }}</p>
        </div>
        <div class="modal-body">
          <div class="note-textarea">{{ selectedNote.note }}</div>
        </div>
        <div class="modal-foot">
          <button class="btn solid" @click="showNoteModal = false">关闭</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'

const router = useRouter()
const goBack = () => {
  router.back()
}

type WeekDay = { date: number; day: string; fullDate: string; isToday: boolean }

type DayRecord = { checked: boolean; note: string }

type CheckinData = Record<string, Record<string, DayRecord>>

const currentUser = '唐怡'
const members = ref<string[]>(['江秋月', '陈茜', '唐怡'])
const todayNote = ref('')
const showNoteModal = ref(false)
const selectedNote = ref<null | { member: string; date: string; note: string; dayText: string }>(null)

function getWeekDates(weekOffset = 0): WeekDay[] {
  const today = new Date()
  const start = new Date(today)
  start.setDate(today.getDate() - today.getDay() + weekOffset * 7)
  const days = ['日', '一', '二', '三', '四', '五', '六']
  const arr: WeekDay[] = []
  for (let i = 0; i < 7; i++) {
    const d = new Date(start)
    d.setDate(start.getDate() + i)
    const fullDate = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())).toISOString().split('T')[0]
    arr.push({ date: d.getDate(), day: days[i], fullDate, isToday: i === 6 })
  }
  return arr
}

const weekDates = ref<WeekDay[]>(getWeekDates())

function initCheckinData(): CheckinData {
  const data: CheckinData = {}
  const sampleNotes = [
    '跑步30分钟，感觉很棒！',
    '今天控制饮食，多吃了蔬菜',
    '做了瑜伽和拉伸运动',
    '步行8000步，达成目标',
    '健身房力量训练1小时',
    '晚餐只吃了沙拉，很满足',
    '爬楼梯代替坐电梯',
  ]
  members.value.forEach((m) => {
    data[m] = {}
    weekDates.value.forEach((day) => {
      const isChecked = m !== currentUser ? Math.random() > 0.4 : Math.random() > 0.6
      data[m][day.fullDate] = {
        checked: isChecked,
        note: isChecked ? sampleNotes[Math.floor(Math.random() * sampleNotes.length)] : '',
      }
    })
  })
  return data
}

const checkinData = ref<CheckinData>(initCheckinData())

function handleCheckin(member: string, date: string, note = '') {
  if (member !== currentUser) return
  const rec = checkinData.value[member][date]
  const toggled = !rec.checked
  checkinData.value[member][date] = { checked: toggled, note: toggled ? (note || rec.note) : rec.note }
}

function handleViewNote(member: string, date: string) {
  const rec = checkinData.value[member][date]
  if (rec.checked && rec.note) {
    const d = weekDates.value.find((w) => w.fullDate === date)!
    selectedNote.value = { member, date, note: rec.note, dayText: `${d.date}日 (${d.day})` }
    showNoteModal.value = true
  }
}

function handleTodayCheckin() {
  const today = weekDates.value.find((w) => w.isToday)
  if (!today) return
  if (todayNote.value.trim()) {
    handleCheckin(currentUser, today.fullDate, todayNote.value.trim())
    todayNote.value = ''
  }
}

function getCompletionRate(member: string) {
  const entries = Object.values(checkinData.value[member])
  const completed = entries.filter((d) => d.checked).length
  return Math.round((completed / 7) * 100)
}

const ranking = computed(() => members.value.map((name) => ({ name, rate: getCompletionRate(name) })).sort((a, b) => b.rate - a.rate))
const userRank = computed(() => ranking.value.findIndex((r) => r.name === currentUser) + 1)

function onDayCellClick(member: string, fullDate: string) {
  if (member === currentUser) {
    handleCheckin(member, fullDate)
  } else {
    handleViewNote(member, fullDate)
  }
}
</script>

<style scoped>
:root {
  --bg-1: #FFF7ED;
  /* amber-50 */
  --bg-2: #FFEDD5;
  /* orange-100 */
  --brand-1: #34D399;
  /* emerald-400 */
  --brand-2: #14B8A6;
  /* teal-500 */
  --text-1: #111827;
  /* gray-900 */
  --text-2: #374151;
  /* gray-700 */
  --muted: #6B7280;
  /* gray-500 */
  --line: #FCD34D;
  /* amber-300 */
  --line-2: #E5E7EB;
  /* gray-200 */
  --ok: #059669;
  /* emerald-600 */
  --ok-weak: #A7F3D0;
  /* emerald-200 */
}

* {
  box-sizing: border-box;
}

html,
body,
.app {
  margin: 0;
  padding: 0;
}

.app {
  min-height: 100vh;
  background: linear-gradient(135deg, var(--bg-1), var(--bg-2));
}

.container {
  width: 100%;
  max-width: 768px;
  padding: 16px;
}

/* header */
.app-header {
  position: sticky;
  top: 0;
  z-index: 10;
  backdrop-filter: saturate(140%) blur(6px);
  background: rgba(255, 255, 255, .9);
  border-bottom: 1px solid var(--line);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand {
  display: flex;
  gap: 12px;
  align-items: center;
}

.brand-icon {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--brand-1), var(--brand-2));
  display: grid;
  place-items: center;
}

.brand-icon .icon {
  width: 22px;
  height: 22px;
  color: #fff;
}

.title {
  margin: 0;
  font-size: 18px;
  color: var(--text-1);
  font-weight: 700;
}

.subtitle {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--muted);
}

.rank-box {
  text-align: right;
}

.rank {
  color: var(--ok);
  font-weight: 600;
}

.rank-sub {
  color: var(--muted);
  font-size: 12px;
}

/* card */
.card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
  padding: 16px;
  margin-bottom: 16px;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.card-title {
  margin: 0;
  font-size: 15px;
  color: var(--text-1);
  font-weight: 600;
}

.card-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 12px;
}

.meta-icon {
  width: 14px;
  height: 14px;
}

/* week header */
.week-head {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 6px;
  margin-bottom: 12px;
}

.week-head .cell {
  text-align: center;
}

.dow {
  font-size: 12px;
  color: #4B5563;
  font-weight: 600;
}

.dom {
  margin-top: 2px;
  font-size: 12px;
  color: #9CA3AF;
}

.dom.today {
  color: var(--ok);
  font-weight: 700;
}

.muted {
  color: #9CA3AF;
  font-size: 12px;
  padding: 8px 0;
}

/* member rows */
.member-list {
  display: grid;
  gap: 10px;
}

.member-row {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 6px;
  padding: 10px;
  border: 2px solid #F3F4F6;
  border-radius: 12px;
  background: #FAFAFA;
}

.member-row.me {
  background: linear-gradient(90deg, #FFFBEB, #FFF7ED);
  border-color: #FDE68A;
}

.member-meta {
  text-align: center;
}

.member-meta .name {
  font-size: 12px;
  color: #374151;
  font-weight: 600;
  margin-bottom: 2px;
}

.member-meta .rate {
  font-size: 12px;
  color: var(--ok);
  font-weight: 700;
}

.me-badge {
  color: var(--ok);
  margin-left: 4px;
}

.trophy {
  width: 12px;
  height: 12px;
  color: #F59E0B;
  display: block;
  margin: 4px auto 0;
}

.check-cell {
  display: flex;
  justify-content: center;
}

.check-btn {
  width: 28px;
  height: 28px;
  border-radius: 999px;
  border: 2px solid var(--line-2);
  background: #fff;
  display: grid;
  place-items: center;
  position: relative;
  transition: transform .15s, border-color .15s, box-shadow .15s;
}

.check-btn.today {
  box-shadow: 0 0 0 3px rgba(16, 185, 129, .18);
}

.check-btn.unchecked {
  cursor: pointer;
}

.check-btn.unchecked:hover {
  border-color: var(--ok-weak);
}

.check-btn.checked {
  color: #fff;
  border-color: #6EE7B7;
  background: linear-gradient(135deg, #34D399, #0D9488);
  box-shadow: 0 1px 4px rgba(13, 148, 136, .25);
}

.check-btn.peekable:hover {
  transform: scale(1.08);
  cursor: pointer;
}

.icon-s {
  width: 16px;
  height: 16px;
}

.dot {
  position: absolute;
  right: -3px;
  top: -3px;
  width: 8px;
  height: 8px;
  background: #F59E0B;
  border-radius: 50%;
  border: 1px solid #fff;
}

/* ranking */
.ranking {
  display: grid;
  gap: 10px;
}

.rank-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  border-radius: 12px;
  background: #F9FAFB;
}

.rank-row.mine {
  background: linear-gradient(90deg, #FFFBEB, #FFF7ED);
  border: 1px solid #FDE68A;
}

.rank-left {
  display: flex;
  align-items: center;
  gap: 10px;
}

.rank-no {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
}

.rank-no.no-1 {
  background: #FEF3C7;
  color: #92400E;
}

.rank-no.no-2 {
  background: #F3F4F6;
  color: #374151;
}

.rank-no.no-3 {
  background: #FFEDD5;
  color: #7C2D12;
}

.rank-name {
  font-weight: 600;
  color: #374151;
}

.rank-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.rate-strong {
  color: var(--ok);
  font-weight: 700;
}

.rate-sub {
  color: #6B7280;
  font-size: 12px;
}

/* 今日打卡 */
.mb {
  margin-bottom: 8px;
}

.field .textarea {
  width: 100%;
  height: 90px;
  padding: 10px 12px;
  border: 1px solid var(--line-2);
  border-radius: 10px;
  resize: none;
  outline: none;
  font-size: 14px;
  transition: box-shadow .2s, border-color .2s;
}

.field .textarea:focus {
  border-color: var(--ok-weak);
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.15);
}

.hint {
  margin-top: 4px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.muted {
  color: #9CA3AF;
  font-size: 12px;
}

.btn {
  appearance: none;
  border: 0;
  padding: 12px;
  border-radius: 12px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
}

.btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

.btn.primary {
  color: #065F46;
  border: 2px solid #FCD34D;
  width: 100%;
  background: linear-gradient(90deg, #FFF7ED, #FFEDD5);
}

.btn.primary:hover {
  filter: brightness(1.03);
}

.btn.done {
  color: #fff;
  border: 2px solid #6EE7B7;
  background: linear-gradient(90deg, #10B981, #0D9488);
  box-shadow: 0 6px 16px rgba(16, 185, 129, .25);
}

.btn.solid {
  color: #fff;
  background: linear-gradient(90deg, #10B981, #0D9488);
}

.icon-m {
  width: 18px;
  height: 18px;
}

.note-panel {
  margin-top: 10px;
  border: 1px solid #FCD34D;
  background: linear-gradient(90deg, #FEF3C7, #FFEDD5);
  border-radius: 10px;
  padding: 10px;
}

.note-label {
  color: #047857;
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 4px;
}

.note-text {
  color: #374151;
  font-size: 14px;
  line-height: 1.6;
}

/* tip */
.tip {
  margin: 16px 0 28px;
  padding: 14px 16px;
  border: 1px solid #FCD34D;
  border-radius: 12px;
  background: linear-gradient(90deg, #FEF3C7, #FFEDD5);
  display: flex;
  align-items: center;
  gap: 12px;
}

.tip-icon .icon {
  width: 18px;
  height: 18px;
  color: var(--ok);
}

.tip-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: #065F46;
}

.tip-desc {
  margin: 4px 0 0;
  font-size: 12px;
  color: #047857;
}

/* modal */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .5);
  display: grid;
  place-items: center;
  padding: 16px;
  z-index: 50;
}

.modal-panel {
  width: 100%;
  max-width: 420px;
  border-radius: 14px;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .25);
}

.modal-head {
  padding: 12px 16px;
  border-bottom: 1px solid #FDE68A;
  background: linear-gradient(90deg, #FEF3C7, #FFEDD5);
}

.modal-title {
  margin: 0;
  color: #1F2937;
  font-weight: 700;
}

.modal-sub {
  margin: 4px 0 0;
  color: #6B7280;
  font-size: 12px;
}

.modal-body {
  padding: 16px;
}

.note-textarea {
  background: #F9FAFB;
  border-radius: 10px;
  padding: 10px;
  color: #374151;
  font-size: 14px;
  line-height: 1.7;
}

.modal-foot {
  padding: 0 16px 16px;
}

@media (max-width: 420px) {
  .title {
    font-size: 16px;
  }
}

.back-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: #374151;
  padding: 6px;
  border-radius: 6px;
  transition: background-color .2s;
}
.back-btn:hover {
  background-color: rgba(0,0,0,0.05);
}
</style>
